/**
 * @author Rid King
 * @since 2017-04-29
 * @version 2.0.0
 * @description 链条类
 */

// 状态
const _STATUS_ = {
    PENDING: 0, // 等待
    READY: 1, // 准备完成
    FULFILLED: 2, // 已完成
    REJECTED: 3, // 已拒绝
    FINAlE: 4, // 到达终点
    COMPLETE: 5 // 链条完成
}

// 模式
const _MODE_ = {
    NORMAL: 0, // 普通模式
    RESTART: 1 // 重启模式
}

/**
 * @description 链接构造函数
 * @param construct <Function> 构造体
 * 构造体参数
 * resolve <Function> 对象的状态从“未完成”变为“成功”（即从 pending 变为 resolved），在异步操作成功时调用，并将异步操作的结果，作为参数传递出去
 * reject <Function> 对象的状态从“未完成”变为“失败”（即从 pending 变为 rejected），在异步操作失败时调用，并将异步操作报出的错误，作为参数传递出去
*/
class Chain {
    // 构造函数
    constructor (construct) {
        let me = this
        let buckles = [] // 链条扣
        let backups = [] // 备份链条
        let status = _STATUS_.PENDING // 初始状态为等待状态
        let mode = _MODE_.NORMAL // 当前链条模式
        let conclusion = undefined // 保存运行结果作为参数

        /**
         * @description 添加成功回调
         * @param type <Function> 回调类型，存在值：_STATUS_.FULFILLED,REJECTED,FINAlE
         * @param resolve <Function> 回调函数
         * @param reject <Function> 失败回调
        */
        this._push = function (type, resolve, reject) {
            var buckle

            // 成功与失败链扣
            if (type === _STATUS_.FULFILLED) {
                // 成功链扣
                buckle = new Buckle(resolve, _STATUS_.FULFILLED)
                buckles.push(buckle)
                // 备份链扣
                backups.push(buckle)

                // 失败链扣
                if (typeof reject !== 'undefined') {
                    buckle = new Buckle(reject, _STATUS_.REJECTED)
                    buckles.push(buckle)
                    // 备份链扣
                    backups.push(buckle)
                }
            }
            // 添加链扣失败回调
            else if (type === _STATUS_.REJECTED) {
                buckle = new Buckle(resolve, _STATUS_.REJECTED)
                buckles.push(buckle)
                // 备份链扣
                backups.push(buckle)
            }
            // 添加链扣终点回调
            else if (type === _STATUS_.FINAlE) {
                buckle = new Buckle(resolve, _STATUS_.FINAlE)
                buckles.push(buckle)
                // 备份链扣
                backups.push(buckle)
            }

            // 执行
            this._launch()
        }

        /**
         * @description 监测执行
        */
        this._launch = function () {
            if (status === _STATUS_.PENDING) {
                return false
            }

            // 正常运行
            handler([conclusion])
        }

        /**
         * @description 链式当前状态
        */
        this.state = function () {
            return status
        }

        /**
         * @description 获取链条结果
         * @return <any>
        */
        // this.getConclusion = function () {
        //     return conclusion
        // }

        /**
         * @description 完成运行
        */
        this.resolve = function () {
            // 设置状态为完成
            status = _STATUS_.FULFILLED
            this._launch()
            return this
        }

        /**
         * @description 拒绝运行
        */
        this.reject = function () {
            // 设置状态为拒绝
            status = _STATUS_.REJECTED
            this._launch()
            return this
        }

        /**
         * @description 停止链式操作
        */
        this.stop = function () {
            // 设置状态为等待
            status = _STATUS_.PENDING
            return this
        }

        /**
         * @description 链式重新开始
        */
        this.restart = function () {
            // 已经是重启状态不执行
            if (mode === _MODE_.RESTART) {
                return this
            }

            // 将模式设置为重启
            mode = _MODE_.RESTART

            // 重置链扣组
            buckles = []

            // 重置备份链条组状态
            backups.forEach(function (backle) {
                // backups[i].reset()
                buckles.push(backle)
            })

            // 重置状态
            status = _STATUS_.PENDING

            // 启动
            _construct()

            return this
        }

        /**
         * @description 合并链条
         * @param chain <Chain>
        */
        this.rob = function (chain) {
            var me = this

            // 停止运行
            this.stop()
            // 链条添加到尾部
            chain.finally(function (result) {
                // 重置状态与结果
                status = chain.state()
                conclusion = result
                // 链条启动
                me._launch()
            })
        }

        /**
         * @description 完成链式操作
        */
        this.done = function () {
            // 状态设置为已完成
            status = _STATUS_.COMPLETE
            // 清空链扣组
            buckles = []
        }

        /**
         * @description 处理器
         * @param args <Array> 参数数组
        */
        function handler (args) {
            /*判断模式，是否调用了本地方法*/
            // 重启模式停止链条，等链条重新启动
            if (mode === _MODE_.RESTART) {
                // 重新设置链条状态
                mode = _MODE_.NORMAL
                return false
            }

            /*判断状态*/
            // 等待状态
            if (status === _STATUS_.PENDING) {
                return false
            }

            // 链扣选择
            var buckle = buckles[0]

            // 链扣不存在
            if (!buckle){
                return false
            }

            // 删除链扣
            buckles.shift()

            // 定义回调函数
            let callback = undefined
            // 链扣已经执行完成,执行下一个链扣
            // if (buckle.status === _STATUS_.COMPLETE) {
            //     return handler([conclusion])
            // }
            // 链条状态与链扣状态相同或链扣状态是终点则取出回调
            /*else */if (buckle.status === status || buckle.status === _STATUS_.FINAlE) {
                callback = buckle.solve
            }
            // buckle.status !== status
            else {
                return handler([conclusion])
            }

            // 非函数直接取其值
            var result
            if (typeof callback !== 'function') {
                result = callback
            }
            // 执行回调
            else {
                try {
                    result = callback.apply(me, args)
                }
                // 异常执行reject
                catch (e) {
                    result = e
                    status = _STATUS_.REJECTED
                    return handler([result])
                }
            }

            // 终点及以后状态不保存结果
            if (buckle.status < _STATUS_.FINAlE) {
                // 保存运行结果
                conclusion = result
            }

            // 状态设置为完成
            // buckle.status = _STATUS_.COMPLETE

            // 结果是新的链条
            if (result instanceof Chain) {
                me.rob(result)
            }
            // 执行下一个回调
            else {
                return handler([conclusion])
            }
        }

        // 保存构造体
        var _construct = function () {
            // 异步构造，使链扣提前载入
            setTimeout(function () {
                // 运行构造函数
                construct(function () {
                    // 改变状态为成功
                    status = _STATUS_.FULFILLED
                    // 开始执行成功回调
                    handler.apply(me, [arguments])
                }, function () {
                    // 改变状态为失败
                    status = _STATUS_.REJECTED
                    // 开始执行失败回调
                    handler.apply(me, [arguments])
                })
            }, 20)
        }

        // 初始执行
        _construct()
    }

    /**
     * @description 状态改变时的添加回调函数
     * @param resolve <Function> 成功回调
     * @param reject <Function> 失败回调
     * @return <Chain>
    */
    then (resolve, reject) {
        this._push(_STATUS_.FULFILLED, resolve, reject)
        return this
    }

    /**
     * @description then(null, rejection)的别名，用于指定发生错误时的回调函数
     * @param reject <Function> 失败回调
     * @return <Chain>
    */
    catch (reject) {
        this._push(_STATUS_.REJECTED, reject)
        return this
    }

    /**
     * @description 指定不管 Promise 对象最后状态如何，都会执行的回调函数
     * @param finale <Function> 最终回调
     * @return <Chain>
    */
    finally (finale) {
        this._push(_STATUS_.FINAlE, finale)
        return this
    }

    /**
     * @description 返回一个新的链条，所有参数链条执行完成后再执行这个链扣组
     * @param chains <Array[Chain]> 链条数组
     * @return <Chain>
    */
    static all (chains) {
        var len = 0, arr = []
        // 判断参数是否是数组
        if (!Array.isArray(chains)) {
            // 返回空的新链条
            return new Chain(function(resolve, reject) {})
        } 
        // 过虑符合条件的链条
        else {
            // 遍历数组
            chains.forEach(function (chain) {
                // 属于链条实例
                if (chain instanceof Chain) {
                    len += 1
                    arr.push(chain)
                }
            })
        }

        // 返回新链条
        return new Chain(function(resolve, reject) {
            var count = 0
            // 遍历数组，过虑符合条件的链条
            arr.forEach(function (chain) {
                chain.then(function (result) {
                    // 计数累加
                    count += 1
                    // 参数链条执行完成，开始执行此链条
                    if (count === len) {
                        resolve(result)
                    }
                }, function (result) {
                    // 计数累加
                    count += 1
                    // 参数链条执行完成，开始执行此链条
                    if (count === len) {
                        reject(result)
                    }
                })
            })
        })
    }

    /**
     * @description 返回一个新的链条，所有参数链条中，任意一个执行完成，再执行这个链扣组
     * @param chains <Array[Chain]> 链条数组
     * @return <Chain>
    */
    static race (chains) {
        var isRun = false, arr = []
        // 判断参数是否是数组
        if (!Array.isArray(chains)) {
            // 返回空的新链条
            return new Chain(function(resolve, reject) {})
        } 
        // 过虑符合条件的链条
        else {
            // 遍历数组
            chains.forEach(function (chain) {
                // 属于链条实例
                if (chain instanceof Chain) {
                    arr.push(chain)
                }
            })
        }

        // 返回新链条
        return new Chain(function(resolve, reject) {
            // 遍历数组，过虑符合条件的链条
            arr.forEach(function (chain) {
                chain.then(function (result) {
                    // 判断是否已经执行
                    if (isRun) {
                        return false
                    }
                    isRun = true
                    // 开始执行此链条
                    resolve(result)
                }, function (result) {
                    // 判断是否已经执行
                    if (isRun) {
                        return false
                    }
                    isRun = true
                    // 开始执行此链条
                    reject(result)
                })
            })
        })
    }

    /**
     * @description 返回一个以给定值解析后的Promise对象
     * @param param <any> 提供的回调参数，可为普通值或Chain实例
     * @return <Chain>
    */
    static resolve (param) {
        var chain = new Chain(function(resolve){
            resolve(param)
        })
        return chain
    }

    /**
     * @description 返回一个用reason拒绝的Promise
     * @param param <any> 提供的回调参数，可为普通值或Chain实例
     * @return <Chain>
    */
    static reject (param) {
        var chain = new Chain(function(resolve, reject){
            reject(param)
        })
        return chain
    }
}

/**
 * @description 链条的搭扣，扣环
 * @param solve <Function> 回调函数
 * @param status <_STATUS_> 状态
*/
class Buckle {
    constructor (solve, status) {
        //保存私有状态
        let _status = status
        // 链扣状态
        this.status = status

        // 处理回调
        this.solve = solve

        // 重置状态
        this.reset = function () {
            this.status = _status
        }
    }
}

export default Chain